#include "MetaTable.h"
#include <map>


namespace impl
{
	std::map<TypeID, MetaClass*> metaTables;
}

MetaClass* MetaClass::getMetaClass(const char* className)
{
	for (auto it = impl::metaTables.begin(); it != impl::metaTables.end(); ++it)
	{
		if (strcmp(it->second->name, className) == 0)
			return it->second;
	}

	return nullptr;
}

MetaClass* MetaClass::getMetaClass( TypeID type )
{
	return impl::metaTables[type];
}

MetaClass::MetaClass( const char* cName, TypeID type ) :
	base(nullptr),
	name(cName),
	typeID(type)
{
	impl::metaTables[typeID] = this;
}

MetaFunction* MetaClass::getMethod( TypeID nameID, TypeID signature, bool searchInBase/*=true */ ) const
{
	for (unsigned int i = 0; i < functions.size(); ++i)
	{
		MetaFunction* f = functions.at(i);
		if (f->nameID == nameID && f->signature == signature)
			return f;
	}

	if (searchInBase && base)
	{
		return base->getMethod(nameID, signature, searchInBase);
	}

	return nullptr;
}

bool MetaClass::isSubclass( TypeID type ) const
{
	const MetaClass* table = this;
	while (table != nullptr)
	{
		if (table->typeID == type)
			return true;
		table = table->base;
	}

	return false;
}

MetaVariable* MetaClass::getVariable( TypeID nameID ) const
{
	for (unsigned int i = 0; i < variables.size(); ++i)
	{
		MetaVariable* f = variables.at(i);
		if (f->nameID == nameID)
			return f;
	}

	if ( base)
	{
		return base->getVariable(nameID);
	}

	return nullptr;
}

void* MetaClass::construct()
{
	MetaConstructor* c = getConstructor();
	return c ? c->call() : nullptr;
}

MetaConstructor* MetaClass::getConstructor( TypeID signatureID /*= getTypeID< void() >()*/ )
{
	for (auto it = constructors.begin(); it != constructors.end(); ++it)
	{
		if ((*it)->signature == signatureID)
			return *it;
	}

	return nullptr;
}

MetaSignal* MetaClass::getSignal( TypeID nameID ) const
{
	for (unsigned int i = 0; i < signals.size(); ++i)
	{
		MetaSignal* f = signals.at(i);
		if (f->nameID == nameID)
			return f;
	}

	if ( base)
	{
		return base->getSignal(nameID);
	}

	return nullptr;
}

TypeID impl::getNextTypeID()
{
	static TypeID type= 0;
	return ++type;
}

